package com.ssy.lingxi.message.serviceimpl;

import com.ssy.lingxi.common.constant.manage.ShopTypeEnum;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.model.vo.PageVO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.message.api.vo.request.*;
import com.ssy.lingxi.message.api.vo.response.MessageResponse;
import com.ssy.lingxi.message.constant.MessageConstants;
import com.ssy.lingxi.message.entity.MemberMessage;
import com.ssy.lingxi.message.entity.PushDevice;
import com.ssy.lingxi.message.enums.CommonBooleanEnum;
import com.ssy.lingxi.message.enums.MessageBusinessTypeEnum;
import com.ssy.lingxi.message.enums.MessageNoticeEnum;
import com.ssy.lingxi.message.enums.MessageTypeEnum;
import com.ssy.lingxi.message.jpush.AliasUtil;
import com.ssy.lingxi.message.jpush.JPushService;
import com.ssy.lingxi.message.model.vo.PushMessageIdResponse;
import com.ssy.lingxi.message.repository.MemberMessageRepository;
import com.ssy.lingxi.message.repository.PushDeviceRepository;
import com.ssy.lingxi.message.service.IMemberMessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 会员消息服务实现类
 * @author yzc
 * @version 2.0.0
 * @date 2020/10/27
 */
@Slf4j
@Service
public class MemberMessageServiceImpl extends BaseMemberMessageService implements IMemberMessageService {
    @Resource
    private MemberMessageRepository memberMessageRepository;
    @Resource
    private PushDeviceRepository pushDeviceRepository;
    @Resource
    private JPushService jPushService;
    @Resource
    private MessageEventService messageEventService;
    @Resource
    private MemberFeignService memberFeignService;

    @Override
    public Wrapper<PageData<MessageResponse>> pageMemberMessage(PageVO request, UserLoginCacheDTO loginUser) {
        // 拉取平台消息
        this.basePullMainMessage(loginUser.getMemberId(), loginUser.getMemberRoleId(), loginUser.getUserId());

        // 消息分页列表
        Pageable page = PageRequest.of(request.getCurrent() - 1, request.getPageSize(), Sort.by("sendTime").descending());
        Page<MemberMessage> pageList = memberMessageRepository.findAll((Specification<MemberMessage>) (root, query, cb) -> {
            List<Predicate> predicateList = new ArrayList<>();
            predicateList.add(cb.equal(root.get("recMemberId"), loginUser.getMemberId()));
            predicateList.add(cb.equal(root.get("recRoleId"), loginUser.getMemberRoleId()));
            predicateList.add(cb.equal(root.get("recUserId"), loginUser.getUserId()));

            Predicate[] p = new Predicate[predicateList.size()];
            return query.where(predicateList.toArray(p)).getRestriction();
        }, page);

        List<MessageResponse> resultList = pageList.stream().map(e -> {
            MessageResponse response = new MessageResponse();
            response.setId(e.getId());
            response.setType(e.getType());
            response.setTitle(e.getTitle());
            response.setContent(e.getContent());
            response.setUrl(e.getUrl());
            response.setStatus(e.getStatus());
            response.setSendTime(e.getSendTime());
            return response;
        }).collect(Collectors.toList());
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), resultList));
    }

    @Override
    public Wrapper<PageData<MessageResponse>> pagePlatformMessage(PageVO request, UserLoginCacheDTO loginUser) {
        // 消息分页列表
        Pageable page = PageRequest.of(request.getCurrent() - 1, request.getPageSize(), Sort.by("sendTime").descending());
        Page<MemberMessage> pageList = memberMessageRepository.findAll((Specification<MemberMessage>) (root, query, cb) -> {
            List<Predicate> predicateList = new ArrayList<>();
            predicateList.add(cb.equal(root.get("recMemberId"), MSG_PF_REC_MEMBER_ID));
            predicateList.add(cb.equal(root.get("recRoleId"), MSG_PF_REC_ROLE_ID));

            Predicate[] p = new Predicate[predicateList.size()];
            return query.where(predicateList.toArray(p)).getRestriction();
        }, page);

        List<MessageResponse> resultList = pageList.stream().map(e -> {
            MessageResponse response = new MessageResponse();
            response.setId(e.getId());
            response.setType(e.getType());
            response.setTitle(e.getTitle());
            response.setContent(e.getContent());
            response.setUrl(e.getUrl());
            response.setStatus(e.getStatus());
            response.setSendTime(e.getSendTime());
            return response;
        }).collect(Collectors.toList());
        return Wrapper.success(new PageData<>(pageList.getTotalElements(), resultList));

    }

    @Override
    public int countUnreadMemberMessage(Long memberId, Long roleId, Long userId) {
        long count = memberMessageRepository.countByRecMemberIdAndRecRoleIdAndRecUserIdAndStatus(memberId, roleId, userId, CommonBooleanEnum.NO.getCode());
        // 返回
        return Long.valueOf(count).intValue();
    }

    @Override
    public int countUnreadPlatformMessage() {
        long count = memberMessageRepository.countByRecMemberIdAndRecRoleIdAndRecUserIdAndStatus(MSG_PF_REC_MEMBER_ID, MSG_PF_REC_ROLE_ID, MSG_PF_REC_USER_ID, CommonBooleanEnum.NO.getCode());
        // 返回
        return Long.valueOf(count).intValue();
    }

    @Override
    public void pullMainMessage(Long recMemberId, Long recRoleId, Long recUserId) {
        // 拉取平台消息
        this.basePullMainMessage(recMemberId, recRoleId, recUserId);
    }

    @Override
    public Wrapper<Void> updateReadMemberMessage(MessageIdRequest request, UserLoginCacheDTO loginUser) {
        MemberMessage message = memberMessageRepository.findById(request.getId()).orElse(null);
        if (Objects.isNull(message)) {
            return Wrapper.fail(ResponseCode.MSG_MESSAGE_NOT_FOUND);
        }

        message.setStatus(CommonBooleanEnum.YES.getCode());
        memberMessageRepository.saveAndFlush(message);

        // 推送未读消息数
        messageEventService.onMessage(loginUser.getMemberId(), loginUser.getMemberRoleId(), loginUser.getUserId());

        return Wrapper.success();
    }

    @Override
    public Wrapper<Void> updateReadPlatformMessage(MessageIdRequest request, UserLoginCacheDTO loginUser) {
        MemberMessage message = memberMessageRepository.findById(request.getId()).orElse(null);
        if (Objects.isNull(message)) {
            return Wrapper.fail(ResponseCode.MSG_MESSAGE_NOT_FOUND);
        }

        message.setStatus(CommonBooleanEnum.YES.getCode());
        memberMessageRepository.saveAndFlush(message);

        // 推送未读消息数
        messageEventService.onMessage(MSG_PF_REC_MEMBER_ID, MSG_PF_REC_ROLE_ID, loginUser.getUserId());

        return Wrapper.success();
    }

    @Override
    public Wrapper<Void> updateAllReadMemberMessage(UserLoginCacheDTO loginUser) {
        List<MemberMessage> messageList = memberMessageRepository.findAllByRecMemberIdAndRecRoleIdAndStatus(loginUser.getMemberId(), loginUser.getMemberRoleId(), CommonBooleanEnum.NO.getCode());
        if (CollectionUtils.isEmpty(messageList)) {
            return Wrapper.success();
        }

        List<MemberMessage> saveList = messageList.stream().peek(e -> e.setStatus(CommonBooleanEnum.YES.getCode())).collect(Collectors.toList());
        memberMessageRepository.saveAll(saveList);

        // 推送未读消息数
        messageEventService.onMessage(loginUser.getMemberId(), loginUser.getMemberRoleId(), loginUser.getUserId());

        return Wrapper.success();
    }

    @Override
    public Wrapper<Void> updateAllReadPlatformMessage(UserLoginCacheDTO loginUser) {
        List<MemberMessage> messageList = memberMessageRepository.findAllByRecMemberIdAndRecRoleIdAndStatus(MSG_PF_REC_MEMBER_ID, MSG_PF_REC_ROLE_ID, CommonBooleanEnum.NO.getCode());
        if (CollectionUtils.isEmpty(messageList)) {
            return Wrapper.success();
        }

        List<MemberMessage> saveList = messageList.stream().peek(e -> e.setStatus(CommonBooleanEnum.YES.getCode())).collect(Collectors.toList());
        memberMessageRepository.saveAll(saveList);

        // 推送未读消息数
        messageEventService.onMessage(MSG_PF_REC_MEMBER_ID, MSG_PF_REC_ROLE_ID, loginUser.getUserId());

        return Wrapper.success();
    }

    @Override
    public Wrapper<Void> deleteMemberMessage(MessageIdsRequest request, UserLoginCacheDTO loginUser) {
        List<MemberMessage> messageList = memberMessageRepository.findByIdIn(request.getIds());
        if (CollectionUtils.isEmpty(messageList)) {
            return Wrapper.success();
        }


        List<MemberMessage> saveList = messageList.stream().peek(e -> e.setDeleted(CommonBooleanEnum.YES.getCode())).collect(Collectors.toList());
        memberMessageRepository.saveAll(saveList);

        // 推送未读消息数
        messageEventService.onMessage(loginUser.getMemberId(), loginUser.getMemberRoleId(), loginUser.getUserId());

        return Wrapper.success();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void sendSystemMessage(SystemMessageRequest systemMessageRequest) {
        log.error("发送系统消息SystemMessageRequest: "+systemMessageRequest.toString());
        String messageNoticeName = systemMessageRequest.getMessageNotice();

        // 获取消息模板
        MessageNoticeEnum messageNotice = MessageNoticeEnum.enumMap.get(messageNoticeName);
        if (Objects.isNull(messageNotice)) {
            return;
        }

        // 填充模板信息
        String content = this.messageFormat(messageNotice.getTemplate(), systemMessageRequest.getParams());
        String url = this.urlFormat(messageNotice.getUrl(), systemMessageRequest.getUrlParams());

        if (MessageConstants.ability.equals(messageNotice.getTarget())) {

            List<MemberMessage> memberMessageList = new ArrayList<>();

            // 未指定发送到会员下的用户
            if (Objects.isNull(systemMessageRequest.getUserId())) {
                List<Long> userIds = memberFeignService.getUserByMemberIds(systemMessageRequest.getMemberId());
                memberMessageList = userIds.stream().map(userId -> {
                    MemberMessage memberMessage = new MemberMessage();
                    memberMessage.setSendMemberId(0L);
                    memberMessage.setSendRoleId(0L);
                    memberMessage.setRecMemberId(systemMessageRequest.getMemberId());
                    memberMessage.setRecRoleId(systemMessageRequest.getRoleId());
                    memberMessage.setRecUserId(userId);
                    memberMessage.setTitle(messageNotice.getTitle());
                    memberMessage.setBusinessType(messageNotice.getBusinessType());
                    memberMessage.setContent(content);
                    memberMessage.setUrl(url);
                    memberMessage.setAppUrl(messageNotice.getAppUrl());
                    memberMessage.setDeleted(CommonBooleanEnum.NO.getCode());
                    memberMessage.setStatus(CommonBooleanEnum.NO.getCode());
                    memberMessage.setType(MessageTypeEnum.SYSTEM.getCode());
                    memberMessage.setSendTime(System.currentTimeMillis());
                    memberMessage.setCreateTime(System.currentTimeMillis());
                    return memberMessage;
                }).collect(Collectors.toList());
            } else {
                // 指定发送到会员下的用户
                MemberMessage memberMessage = new MemberMessage();
                memberMessage.setSendMemberId(0L);
                memberMessage.setSendRoleId(0L);
                memberMessage.setRecMemberId(systemMessageRequest.getMemberId());
                memberMessage.setRecRoleId(systemMessageRequest.getRoleId());
                memberMessage.setRecUserId(systemMessageRequest.getUserId());
                memberMessage.setTitle(messageNotice.getTitle());
                memberMessage.setBusinessType(messageNotice.getBusinessType());
                memberMessage.setContent(content);
                memberMessage.setUrl(url);
                memberMessage.setAppUrl(messageNotice.getAppUrl());
                memberMessage.setDeleted(CommonBooleanEnum.NO.getCode());
                memberMessage.setStatus(CommonBooleanEnum.NO.getCode());
                memberMessage.setType(MessageTypeEnum.SYSTEM.getCode());
                memberMessage.setSendTime(System.currentTimeMillis());
                memberMessage.setCreateTime(System.currentTimeMillis());
                memberMessageList.add(memberMessage);
            }

            memberMessageRepository.saveAll(memberMessageList);

            // 推送未读消息数
            memberMessageList.forEach(memberMessage -> {
                messageEventService.onMessage(memberMessage.getRecMemberId(), memberMessage.getRecRoleId(), memberMessage.getRecUserId());

                if (Arrays.stream(MessageBusinessTypeEnum.values()).anyMatch(e -> e.getCode().equals(messageNotice.getBusinessType()))) {
                    List<PushDevice> pushDeviceList = pushDeviceRepository.findAllByMemberIdAndRoleIdAndUserId(systemMessageRequest.getMemberId(), systemMessageRequest.getRoleId(), systemMessageRequest.getUserId());
                    if (!CollectionUtils.isEmpty(pushDeviceList)) {
                        PushMessageIdResponse pushMessageIdResponse = new PushMessageIdResponse();
                        pushMessageIdResponse.setMessageId(memberMessage.getId());
                        jPushService.pushMessage(content, Arrays.asList(AliasUtil.getAlias(systemMessageRequest.getMemberId(), systemMessageRequest.getRoleId(), systemMessageRequest.getUserId())), pushMessageIdResponse);
                    }
                }
            });

        } else if (MessageConstants.platform.equals(messageNotice.getTarget())) {
            MemberMessage memberMessage = new MemberMessage();
            memberMessage.setSendMemberId(MSG_PF_SEND_MEMBER_ID);
            memberMessage.setSendRoleId(MSG_PF_SEND_ROLE_ID);
            memberMessage.setRecMemberId(MSG_PF_REC_MEMBER_ID);
            memberMessage.setRecRoleId(MSG_PF_REC_ROLE_ID);
            memberMessage.setRecUserId(MSG_PF_REC_USER_ID);
            memberMessage.setTitle(messageNotice.getTitle());
            memberMessage.setBusinessType(messageNotice.getBusinessType());
            memberMessage.setContent(content);
            memberMessage.setUrl(url);
            memberMessage.setAppUrl(messageNotice.getAppUrl());
            memberMessage.setDeleted(CommonBooleanEnum.NO.getCode());
            memberMessage.setStatus(CommonBooleanEnum.NO.getCode());
            memberMessage.setType(MessageTypeEnum.SYSTEM.getCode());
            memberMessage.setSendTime(System.currentTimeMillis());
            memberMessage.setCreateTime(System.currentTimeMillis());
            memberMessageRepository.saveAndFlush(memberMessage);

            // 推送未读消息数
            messageEventService.onPlatformMessage();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void batchSendSystemMessage(List<SystemMessageRequest> request) {
        for (SystemMessageRequest systemMessageRequest : request) {
            sendSystemMessage(systemMessageRequest);
        }
    }

    @Override
    public void sendMemberMessage(Long sendMemberId, Long sendRoleId, Long recMemberId, Long recRoleId, MessageNoticeEnum messageNoticeEnum, List<String> params, List<String> urlParams) {
        // 填充模板信息
        String content = this.messageFormat(messageNoticeEnum.getTemplate(), params);
        String url = this.urlFormat(messageNoticeEnum.getUrl(), urlParams);

        List<Long> userIds = memberFeignService.getUserByMemberIds(recMemberId);
        List<MemberMessage> memberMessageList = userIds.stream().map(userId -> {
            MemberMessage memberMessage = new MemberMessage();
            memberMessage.setSendMemberId(sendMemberId);
            memberMessage.setSendRoleId(sendRoleId);
            memberMessage.setRecMemberId(recMemberId);
            memberMessage.setRecRoleId(recRoleId);
            memberMessage.setRecUserId(userId);
            memberMessage.setTitle(messageNoticeEnum.getTitle());
            memberMessage.setBusinessType(messageNoticeEnum.getBusinessType());
            memberMessage.setContent(content);
            memberMessage.setUrl(url);
            memberMessage.setAppUrl(messageNoticeEnum.getAppUrl());
            memberMessage.setDeleted(CommonBooleanEnum.NO.getCode());
            memberMessage.setStatus(CommonBooleanEnum.NO.getCode());
            memberMessage.setType(MessageTypeEnum.SYSTEM.getCode());
            memberMessage.setSendTime(System.currentTimeMillis());
            memberMessage.setCreateTime(System.currentTimeMillis());
            return memberMessage;
        }).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(memberMessageList)) {
            return;
        }
        memberMessageRepository.saveAll(memberMessageList);
    }

    @Override
    public void sendCustomMessage(SystemMessageCustomRequest request) {
        if (Objects.isNull(request.getMemberId()) || Objects.isNull(request.getRoleId())) {
            return;
        }

        List<MemberMessage> memberMessageList = new ArrayList<>();

        if (Objects.isNull(request.getUserId())) {
            List<Long> userIds = memberFeignService.getUserByMemberIds(request.getMemberId());
            memberMessageList = userIds.stream().map(userId -> {
                MemberMessage memberMessage = new MemberMessage();
                memberMessage.setSendMemberId(MSG_PF_SEND_MEMBER_ID);
                memberMessage.setSendRoleId(MSG_PF_SEND_ROLE_ID);
                memberMessage.setRecMemberId(request.getMemberId());
                memberMessage.setRecRoleId(request.getRoleId());
                memberMessage.setRecUserId(userId);
                memberMessage.setTitle(request.getTitle());
                memberMessage.setContent(request.getContent());
                memberMessage.setUrl("");
                memberMessage.setAppUrl("");
                memberMessage.setDeleted(CommonBooleanEnum.NO.getCode());
                memberMessage.setStatus(CommonBooleanEnum.NO.getCode());
                memberMessage.setType(MessageTypeEnum.SYSTEM.getCode());
                memberMessage.setSendTime(System.currentTimeMillis());
                memberMessage.setCreateTime(System.currentTimeMillis());
                return memberMessage;
            }).collect(Collectors.toList());
        } else {
            // 指定发送到会员下的用户
            MemberMessage memberMessage = new MemberMessage();
            memberMessage.setSendMemberId(MSG_PF_SEND_MEMBER_ID);
            memberMessage.setSendRoleId(MSG_PF_SEND_ROLE_ID);
            memberMessage.setRecMemberId(request.getMemberId());
            memberMessage.setRecRoleId(request.getRoleId());
            memberMessage.setRecUserId(request.getUserId());
            memberMessage.setTitle(request.getTitle());
            memberMessage.setContent(request.getContent());
            memberMessage.setUrl("");
            memberMessage.setAppUrl("");
            memberMessage.setDeleted(CommonBooleanEnum.NO.getCode());
            memberMessage.setStatus(CommonBooleanEnum.NO.getCode());
            memberMessage.setType(MessageTypeEnum.SYSTEM.getCode());
            memberMessage.setSendTime(System.currentTimeMillis());
            memberMessage.setCreateTime(System.currentTimeMillis());
        }

        memberMessageRepository.saveAll(memberMessageList);

        // 推送未读消息数
        memberMessageList.forEach(memberMessage -> {
            messageEventService.onMessage(memberMessage.getRecMemberId(), memberMessage.getRecRoleId(), memberMessage.getRecUserId());
        });
    }

    @Override
    public Wrapper<Void> sendInviteMessage(MessageInviteMemberRequest request, UserLoginCacheDTO loginUser) {
        MessageNoticeEnum messageNoticeEnum;
        if (ShopTypeEnum.LOGISTICS.getCode().equals(request.getShopType())) {
            // 物流门户
            messageNoticeEnum = MessageNoticeEnum.pt_logistics_apply_member;
        } else if (ShopTypeEnum.PROCESS.getCode().equals(request.getShopType())) {
            // 加工门户
            messageNoticeEnum = MessageNoticeEnum.pt_production_apply_member;
        } else {
            return Wrapper.fail(ResponseCode.MSG_SEND_INVITE_SHOP_TYPE);
        }

        // 是否发送过
        if (memberMessageRepository.existsBySendMemberIdAndSendRoleIdAndRecMemberIdAndRecRoleIdAndBusinessType(
                loginUser.getMemberId(), loginUser.getMemberRoleId(),
                request.getMemberId(), request.getRoleId(), messageNoticeEnum.getBusinessType())) {
            return Wrapper.fail(ResponseCode.MSG_COMPLETE_SEND_INVITE);
        }

        // 发送消息
        List<String> params = Arrays.asList(loginUser.getCompany(), loginUser.getCompany());
        List<String> urlParams = Arrays.asList(loginUser.getMemberId() + "", loginUser.getMemberRoleId() + "");
        this.sendMemberMessage(loginUser.getMemberId(), loginUser.getMemberRoleId(), request.getMemberId(), request.getRoleId(), messageNoticeEnum, params, urlParams);

        return Wrapper.success();
    }
}
